import json
import urllib.parse
from urllib.request import urlopen
import logging

from itsdangerous import BadData
from itsdangerous import TimedJSONWebSignatureSerializer as TJSSerializer

from django.conf import settings

from oauth import constants
from oauth.exceptions import OAuthQQAPIError

logger = logging.getLogger('django')


class OAuthQQ(object):
    """
    QQ登录辅助类工具
    """

    def __init__(self, client_id=None, redirect_uri=None, state=None, client_secret=None):
        # 申请QQ登录成功后,分配给应用的appid
        self.client_id = client_id or settings.QQ_CLIENT_ID
        # 成功授权后的回调地址，必须是注册appid时填写的主域名下的地址，建议设置为网站
        self.redirect_uri = redirect_uri or settings.QQ_REDIRECT_URI
        # client端的状态值 在这里是前端next带的地址
        self.state = state or settings.QQ_STATE
        # 申请QQ登录成功后，分配给网站的appkey
        self.client_secret = client_secret or settings.QQ_CLIENT_SECRET

    def get_qq_login_url(self):
        """
        发送给前端拼接的url
        :return:
        """
        url = 'https://graph.qq.com/oauth2.0/authorize?'

        # url 后面要拼接的参数
        params = {
            # 授权类型，此值固定为“code”。
            'response_type': 'code',
            'client_id': self.client_id,
            'redirect_uri': self.redirect_uri,
            'state': self.state,
        }

        url += urllib.parse.urlencode(params)
        return url

    def get_access_token(self, code):
        """
        获取access_token
        :param code:
        :return:
        """
        url = 'https://graph.qq.com/oauth2.0/token?'

        params = {
            "grant_type": "authorization_code",
            "client_id": self.client_id,
            "client_secret": self.client_secret,
            "code": code,
            "redirect_uri": self.redirect_uri
        }

        url += urllib.parse.urlencode(params)

        # 向QQ服务器发送请求 access_token
        # access_token=FE04************************CCE2&expires_in=7776000&refresh_token=88E4************************BE14
        try:
            resp = urlopen(url)
            resp_data = resp.read()  # byte
            resp_data = resp_data.decode()  # str

            resp_dict = urllib.parse.parse_qs(resp_data)
        except Exception as e:
            logger.error('获取access_token异常: %s' % e)
            return OAuthQQAPIError
        else:
            # access_token取出是一个列表
            access_token = resp_dict.get('access_token')
            access_token = access_token[0]
        return access_token

    def get_openid(self, access_token):
        """
        从QQ服务器获取openid
        :param access_token:
        :return:
        """
        url = 'https://graph.qq.com/oauth2.0/me?access_token=' + access_token

        # 向QQ服务器发送请求 openid
        try:
            resp = urlopen(url)
            resp_data = resp.read()
            resp_data = resp_data.decode()

            # openid = callback( {"client_id":"YOUR_APPID","openid":"YOUR_OPENID"} );
            # 字符串切割
            resp_data = resp_data[10:-4]
            resp_dict = json.loads(resp_data)
        except Exception as e:
            logger.error('获取openid异常: %s' % e)
            return OAuthQQAPIError
        else:
            openid = resp_dict.get('openid')
        return openid

    def generate_save_user_token(self, openid):
        """
        生成自己服务器的 access_token
        :param openid:
        :return:
        """
        serializer = TJSSerializer(secret_key=settings.SECRET_KEY, expires_in=constants.BIND_USER_ACCESS_TOKEN_EXPIRES)
        access_token = serializer.dumps({'openid': openid})
        return access_token.decode()

    @staticmethod
    def check_save_user_token(access_token):
        """
        从django生成的access_token取出token
        :return:
        """
        serializer = TJSSerializer(secret_key=settings.SECRET_KEY, expires_in=constants.SAVE_QQ_USER_TOKEN_EXPIRES)
        try:
            data = serializer.loads(access_token)
        except BadData:
            return None
        else:
            return data['openid']
